#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
#include <iostream>

#include <string>
#include <math.h>
#include "SDL/SDL.h"

#include "libraries/BM_input.h"
#include "libraries/BM_level.h"
#include "libraries/BM_anitex.h"
#include "libraries/BM_menu.h"
#include "libraries/BM_menu_object.h"
#include "libraries/BM_time.h"
#include "libraries/BM_sound.h"
#include "libraries/BM_init.h"
#include "libraries/BM_camera.h"
#include "libraries/BM_bsp.h" 

// screen width, height, and bit depth
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP     16

// Set up some booleans
#define TRUE  1
#define FALSE 0

enum BM_SCREENS{BM_MENU,BM_GAME};


using namespace std;

int quit_loop = false;

BMCamera Camera;
BMBsp my_bsp;
//SDL_Surface* aim_surface;
//BMTex aim_text;

///////////////////////////////////////////////////

// This is our SDL surface
SDL_Surface *screen;
int cur;
BMKeyboard keyboard;
float x, y, z;
int bmGameLoop();
	BMAniTex ani_tex;
	BMBlock block;
	BMLevel level;
int main( int argc, char **argv ){
    int videoFlags;
    SDL_Event event;
    const SDL_VideoInfo *videoInfo;
    if ( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ){
	    fprintf( stderr, "Video initialization failed: %s\n",
		     SDL_GetError( ) );
	    return 1;
	}
    videoInfo = SDL_GetVideoInfo( );
    if ( !videoInfo ){
	    fprintf( stderr, "Video query failed: %s\n",
		     SDL_GetError( ) );
	    return 1;
	}
    // the flags to pass to SDL_SetVideoMode
    videoFlags  = SDL_OPENGL;          // Enable OpenGL in SDL
    videoFlags |= SDL_GL_DOUBLEBUFFER; // Enable double buffering
    videoFlags |= SDL_HWPALETTE;       // Store the palette in hardware
    //videoFlags |= SDL_RESIZABLE;       // Enable window resizing
    if ( videoInfo->hw_available )
	videoFlags |= SDL_HWSURFACE;
    else
	videoFlags |= SDL_SWSURFACE;
    if ( videoInfo->blit_hw )
	videoFlags |= SDL_HWACCEL;
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,videoFlags );
    if ( !screen ){
	    fprintf( stderr,  "Video mode set failed: %s\n", SDL_GetError( ) );
	    return 1;
	}

    // Enable Texture Mapping ( NEW )
    glEnable( GL_TEXTURE_2D );

    // Enable smooth shading
    glShadeModel( GL_SMOOTH );

    // Set the background black
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

    // Depth buffer setup
    glClearDepth( 1.0f );

    // Enables Depth Testing
    glEnable( GL_DEPTH_TEST );

    // The Type Of Depth Test To Do
    glDepthFunc( GL_LEQUAL );

    // Really Nice Perspective Calculations
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

    // resize the initial window

    GLfloat ratio;

    // Protect against a divide by zero

    ratio = ( GLfloat )SCREEN_WIDTH / ( GLfloat )SCREEN_HEIGHT;

    // Setup our viewport.
    glViewport( 0, 0, ( GLint )SCREEN_WIDTH, ( GLint )SCREEN_HEIGHT );

    // change to the projection matrix and set our viewing volume.
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );

    // Set our perspective
    gluPerspective( 45.0f, ratio, 0.1f, 100.0f );

    // Make sure we're chaning the model view and not the projection
    glMatrixMode( GL_MODELVIEW );

    // Reset The View
    glLoadIdentity( );

    // Camera
    Camera.Move( F3dVector(0.0, 0.0, 3.0 ));
	Camera.MoveForwards( 1.0 );

   //LOAD STUFF HERE
	//level.load("data/level/Smile.lvl");
	level.loadSmile();
	cur = BM_MENU;
	x = 0;
	y = 0;
	z = 0;

	//SDL_ShowCursor(SDL_DISABLE);

	/*if (!aim_text.load("Data/crosshair.bmp")) {
        //Error!
        cout << "Unable to load Data/aim.bmp";
        return -1;
	}*/

    // wait for events
    while ( bmGameLoop() ){
	    while ( SDL_PollEvent( &event ) ){
	        if( event.type == SDL_QUIT)
                return 0;

            switch(cur){
                case BM_GAME:

                    if( event.type == SDL_MOUSEMOTION )
                        Camera.mouseMove(event.motion.x, event.motion.y, SCREEN_WIDTH, SCREEN_HEIGHT);
                break;
            }
	    }
	}

	//aim_text.freeTex();

    // clean ourselves up and exit
    SDL_Quit();

    // Should never get here
    return( 0 );
}

/*void drawCrosshair()
{
    glTranslatef(0.0f,0.0f,-5.0f);

    glBindTexture(GL_TEXTURE_2D, aim_text.getTex());

    glBegin( GL_QUADS );
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// Top Left Of The Texture and Quad

    // Back Face
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// Bottom Left Of The Texture and Quad

    // Top Face
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// Top Right Of The Texture and Quad

    // Bottom Face
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// Bottom Right Of The Texture and Quad

    // Right face
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// Bottom Left Of The Texture and Quad

    // Left Face
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// Top Left Of The Texture and Quad
    glEnd();
}*/

int bmGameLoop(){
	BMTimer timer;
    timer.setFPS(60);
	timer.start();
	keyboard.poll();
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	switch(cur){
		case BM_MENU:
			//place menu function here (cur = menu.run(parameters maybe level, character))
			cur = BM_GAME;
			break;
		case BM_GAME:
			/*if(keyboard.hold(SDLK_UP))
				y -= 5.0f;
			if(keyboard.hold(SDLK_DOWN))
				y += 5.0f;
			if(keyboard.hold(SDLK_LEFT))
				x += 5.0f;
			if(keyboard.hold(SDLK_RIGHT))
				x -= 5.0f;*/
			/*if(keyboard.hold(SDLK_w)) {
				//z += 5.0f;
                camera.x_rot -= 1;
                if (camera.x_rot < -360)
                    camera.x_rot += 360;
            }
			if(keyboard.hold(SDLK_s)) {
				//z -= 5.0f;
                camera.x_rot += 1;
                if (camera.x_rot >360)
                    camera.x_rot -= 360;
            }
            if(keyboard.hold(SDLK_a)) {
				camera.y_rot -= 1;
                if (camera.y_rot < -360)
                    camera.y_rot += 360;
			}
            if(keyboard.hold(SDLK_d)) {
				camera.y_rot += 1;
                if (camera.y_rot >360)
                    camera.y_rot -= 360;
            }*/
            if(keyboard.hold(SDLK_DOWN) || keyboard.hold(SDLK_s)) {
                Camera.MoveForwards( 0.5 ) ;
				my_bsp.back(0.5);
            }
             if(keyboard.hold(SDLK_UP) || keyboard.hold(SDLK_w)) {
                Camera.MoveForwards( -0.5 ) ;
				my_bsp.forward(0.5);
            }
            if(keyboard.hold(SDLK_LEFT) || keyboard.hold(SDLK_a)) {
                Camera.StrafeRight(-0.5);
				my_bsp.left(0.5);

            }
            if(keyboard.hold(SDLK_RIGHT) || keyboard.hold(SDLK_d)) {
                Camera.StrafeRight(0.5);
				my_bsp.right(0.5);
            }
            if(keyboard.hold(SDLK_q)) {
                Camera.StrafeRight(0.5);
				my_bsp.right(0.5);
            }
            if(keyboard.hold(SDLK_ESCAPE)) {
                quit_loop = true;
                break;
            }

            glLoadIdentity();
            Camera.Render();
            //glLoadIdentity();
            //drawCrosshair();

			//y_rot += 1.0f;
			//level.rotate(x_rot,y_rot,z_rot);
			//level.move(x,y,z);
			level.draw();
			//my_bsp.draw();
			break;
		default:
			break;
	}
    SDL_GL_SwapBuffers( );
	timer.frameDelay();

	if (quit_loop)
        return 0;

	return 1;
}
